package com.utils;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.mc.mcvideo.config.Subject;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import javax.annotation.Resource;
import java.util.Date;
import java.util.Map;

/**
 * JWTUtils工具类，生成jwt和解析jwt
 * JSON WEB TOKEN 结构组成：
 * (1)Header(头部)：包含加密算法，通常直接使用 HMAC SHA256
 * (2)Payload(负载)：存放有效信息，比如消息体、签发者、过期时间、签发时间等
 * (3)Signature(签名)：由header(base64后的)+payload(base64后的)+secret(秘钥)三部分组合，然后通过head中声明的算法进行加密
 */
@Slf4j
@Component
@Data
public class JWTUtil {
	private static final String EXP = "exp";
	private static final String PAYLOAD = "payload";
	public static final String USER_COMMON_KEY_PREFIX = "mc_video:common_login_data:";
	public static final int  LOGIN_TOKEN_EXPIRY_DATE = 1000 * 60 * 60 * 24;

	private String secret;
	private JWTVerifier jwtVerifier;

	@Resource
	private RedisUtil redisUtil;

	@Resource
	private JedisPool cacheJedisPool;

	@Value("${jwt.secret}")
	public void setSecret(String secret) {
		this.secret = secret;
		Algorithm algorithm = Algorithm.HMAC256(secret);
		this.jwtVerifier = JWT.require(algorithm).build();
	}



	/**
	 * Token的解密
	 *
	 * @param token  加密后的token
	 * @return
	 */
	public <T> T parseJWT(Class<T> clazz, String token) {
		if (StrUtil.isEmpty(token)) {
			return null;
		}
		try{
			Map<String, Claim> claims1 = this.jwtVerifier.verify(token).getClaims();
			if (claims1.containsKey("exp") && claims1.containsKey("payload")) {
				long exp = ((Claim)claims1.get("exp")).asLong();
				long currentTimeMillis = System.currentTimeMillis() / 1000L;
				if (log.isDebugEnabled()) {
					log.debug("Token expire: " + DateFormatUtils.format(new Date(exp), DateFormatUtils.ISO_8601_EXTENDED_DATETIME_FORMAT.getPattern()));
				}

				if (exp > currentTimeMillis) {
					String json = claims1.get("payload").asString();
					return JSONObject.parseObject(json, clazz);
				}
			}
		}catch (Exception e){
			log.warn("解析token失败,token:{}",token);
		}
		return null;
	}

	public String toLoginTokenString(Subject subject, long maxAge) {
		try {
			String token = this.toTokenString(subject, maxAge);
			String redisKey = USER_COMMON_KEY_PREFIX + subject.getUserId();
			Jedis jedis = this.cacheJedisPool.getResource();
			Throwable var7 = null;

			try {
				jedis.hset(redisKey, "token", token);
				jedis.pexpire(redisKey, maxAge);
			} catch (Throwable var17) {
				var7 = var17;
				throw var17;
			} finally {
				if (jedis != null) {
					if (var7 != null) {
						try {
							jedis.close();
						} catch (Throwable var16) {
							var7.addSuppressed(var16);
						}
					} else {
						jedis.close();
					}
				}

			}
			return token;
		} catch (Exception var19) {
			return null;
		}
	}

	public String toTokenString(Object object, long maxAge) {
		try {
			JWTCreator.Builder builder = JWT.create();
			builder.withClaim("payload", JSONObject.toJSONString(object));
			builder.withExpiresAt(new Date(System.currentTimeMillis() + maxAge));
			return builder.sign(Algorithm.HMAC256(this.secret));
		} catch (Exception var5) {
			return null;
		}
	}

}